#pragma once

#include <wx/ffile.h>
#include <wx/file.h>
#include <wx/thread.h>

#define YYSTYPE char *
extern wxString current_ini_name;  /* current filename/URL being parsed */
extern wxString yyerror_messages;  /* textual parse error messages */
extern int yyerror_count;             /* number of parse errors */

class wxFSFile;
class wxInputStream;
class wxBZipInputStream;

class IniDownloadParseThread;

struct PkgInfo {
	PkgInfo() {
	    source_status = AVAILABLE;
	    binary_status = AVAILABLE;
	}
	
	enum STATUS {
		INVALIDE = -1,
		AVAILABLE = 0,
		UPDATED,
		OUTDATED,
		// actions
		XINSTALL,
		REINSTALL,
		UPGRADE,
		REMOVE,
		PURGE,
	};
	
	wxString name;
	wxString sdesc;
	wxString ldesc;
    wxString version;
    wxArrayString category;
    wxArrayString require;
    wxArrayString dependent;
    
    wxString binary_path;
    wxString binary_size;
    wxString binary_md5;

    wxString source_path;
    wxString source_size;
    wxString source_md5;
    
    STATUS source_status;
    STATUS binary_status;

    wxString installed_bin_version;
    wxString installed_src_version;
    wxString installed_bin_path;
    wxString installed_src_path;
};

struct CatInfo {
	wxString name;
	wxArrayString pkg_names;
};


WX_DECLARE_STRING_HASH_MAP(PkgInfo, PkgHash);
WX_DECLARE_STRING_HASH_MAP(CatInfo, CategoryHash);

class IniBuilder {
    friend class IniDownloadParseThread;
    
public:
	/* Used for selecting a given 'trust' level */
	enum TRUST
	{
	  TRUST_UNKNOWN,
	  TRUST_PREV,
	  TRUST_CURR,
	  TRUST_TEST,
	  NTRUST
	};
	
	static IniBuilder& get() {
		return self;
	}
	
	virtual ~IniBuilder();

    bool parse();
    
    bool regenerate_db();
    
    PkgInfo::STATUS get_pkg_status(const wxString& pkg);
    PkgInfo::STATUS get_pkg_src_status(const wxString& pkg);
    bool set_pkg_status(const wxString& pkg, PkgInfo::STATUS status);
    bool set_pkg_src_status(const wxString& pkg, PkgInfo::STATUS status);
    
    wxString get_pkg_path(const wxString& pkg);
    wxString get_pkg_size_str(const wxString& pkg);
    unsigned long get_pkg_size(const wxString& pkg);
    
    wxArrayString get_pkg_all_dependents(const wxString& pkg);
    wxArrayString get_pkg_all_requires(const wxString& pkg);
    
    bool is_base_pkg(const wxString& pkg);
    bool is_base_pkgs_installed();
    bool mark_all_base_pkgs_installed();
    
    wxArrayString& get_installed_pkgs() {
		return _installed_pkgs;
    }
    
    wxArrayString get_installed_files(const wxString& pkg);
    
    wxString get_installed_version(const wxString& name);
    bool set_installed(const wxString& pkg);
    // bool set_upgraded(const wxString& pkg);
    bool set_removed(const wxString& pkg);

	virtual void buildTimestamp (const char* );
	virtual void buildVersion (const char* );
	virtual void buildPackage (const char* );
	virtual void buildPackageVersion (const char* );
	virtual void buildPackageSDesc (const char* );
	virtual void buildPackageLDesc (const char* );
	virtual void buildPackageInstall (const char* );
	virtual void buildPackageSource (const char*, const char*);
	virtual void buildPackageCategory (const char* );
	virtual void buildPackageRequire (const char* );
	virtual void buildInstallSize (const char*);
	virtual void buildInstallMD5 (char const[16]);
	virtual void buildSourceMD5 (char const[16]);
	virtual void buildPackageTrust (TRUST trust);
	
	unsigned int timestamp;
	wxString version;
	wxString parse_mirror;

    PkgHash packages;
    wxArrayString pkg_names;
    
    CategoryHash categories;
    wxArrayString cat_names;

protected:
	bool _parse_db();
    void _get_pkg_all_dependents(const wxString& pkg, wxArrayString& dependent);
    void _get_pkg_all_requires(const wxString& pkg, wxArrayString& dependent);
    
	wxFFile _inifile;
    wxString _inifile_path;

    wxString setup_version;

    PkgInfo* p_current_pkg;
    wxArrayString _installed_pkgs;
    
    TRUST _trust;

	void _clear_all() {
		cat_names.Clear();
		pkg_names.Clear();
		packages.clear();
		categories.clear();
	}
    
	IniBuilder();
	static IniBuilder self;
};


class IniDownloadParseThread : public wxThread {
public:
	IniDownloadParseThread() : wxThread(wxTHREAD_DETACHED) {}
	virtual ExitCode Entry();
};
